﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace MyCommon
{
    /// <summary>
    /// 对IEnumerable类型的自定义扩展方法
    /// </summary>
    public static class Enumerable
    {
        /// <summary>
        /// 调整平铺式列表为父子关系列表
        /// </summary>
        /// <typeparam name="T">集合内实体的类型，至少具有ID、父ID、子元素集合三个字段</typeparam>
        /// <typeparam name="TItemId">实体的ID属性类型</typeparam>
        /// <param name="list">源列表</param>
        /// <param name="rootId">列表根元素的父ID</param>
        /// <param name="itemIdSelector">取得实体ID的委托</param>
        /// <param name="pIdSelector">取得实体父ID的委托</param>
        /// <param name="fillChildrenAction">为实体填充子集实体的委托</param>
        /// <returns></returns>
        public static IEnumerable<T> AjustToTreeStruct<T, TItemId>(this IEnumerable<T> list, TItemId rootId, Func<T, TItemId> itemIdSelector, Func<T, TItemId> pIdSelector, Action<T, IEnumerable<T>> fillChildrenAction)
            where T : class
        {

            if (list.Any())
            {
                IEnumerable<T> resultList = list.Where(m => Object.Equals(pIdSelector(m), rootId));
                IEnumerable<T> srcList = list.Where(m => !Object.Equals(pIdSelector(m), rootId)).ToList();
                foreach (var item in resultList)
                {
                    var subList = AjustToTreeStruct(srcList, itemIdSelector(item), itemIdSelector, pIdSelector, fillChildrenAction);
                    fillChildrenAction(item, subList);
                    srcList = srcList.Except(subList, new EntityEqualityComparer<T, TItemId>(itemIdSelector)).ToList();
                }
                return resultList;
            }
            return new List<T>();
        }



        /// <summary>
        /// 排序列表，将子级对象排在直接父级对象的后面，TreeGridView控件须先将列表排序才能正常分级显示
        /// 原理，先从旧列表中把根元素移到新列表中，再在旧列表中遍历，每找一个看是否属于新列表中元素的子元素，如果是移到新列表中父元素的后面
        /// </summary>
        /// <typeparam name="T">实体的类型</typeparam>
        /// <typeparam name="TItemId">实体主键的类型</typeparam>
        /// <param name="list">源列表</param>
        /// <param name="rootId">根元素的父Id</param>
        /// <param name="itemIdSelector">获得元素主键的Lambda表达式</param>
        /// <param name="pIdSelector">获得元素父ID的Lambda表达式</param>
        /// <returns></returns>
        public static IEnumerable<T> SortToTreeOrder<T, TItemId>(this IEnumerable<T> list, TItemId rootId, Func<T, TItemId> itemIdSelector, Func<T, TItemId> pIdSelector)
            where T : class
            where TItemId : IEquatable<TItemId>
        {
            var srcList = new List<T>(list);
            var newList = srcList.Where(m => EqualityComparer<TItemId>.Default.Equals(pIdSelector(m), rootId)).ToList();
            srcList = srcList.Except(newList, new EntityEqualityComparer<T, TItemId>(itemIdSelector)).ToList();
            int lastCount;
            do
            {
                lastCount = srcList.Count();
                for (int i = srcList.Count() - 1; i >= 0; i--)
                {
                    bool isBreak = false; ;
                    for (int j = 0, maxj = newList.Count; j < maxj; j++)
                    {
                        if (EqualityComparer<TItemId>.Default.Equals(pIdSelector(srcList[i]), itemIdSelector(newList[j])))
                        {
                            T temp = srcList[i];
                            srcList.Remove(temp);
                            if (j < maxj - 1)
                            {
                                newList.Insert(j + 1, temp);
                            }
                            else
                            {
                                newList.Add(temp);
                            }
                            isBreak = true;
                            break;
                        }
                    }
                    if (isBreak)
                    {
                        break;
                    }
                }
            } while (srcList.Count < lastCount);
            return newList;
        }
        /// <summary>
        /// 对集合随机调整顺序
        /// </summary>
        /// <typeparam name="T">集合元素的类型</typeparam>
        /// <param name="source">源集合</param>
        /// <returns>调整顺序后的集合</returns>
        public static IEnumerable<T> OrderByRandom<T>(this IEnumerable<T> source)
        {
            var buffer = new byte[byte.MaxValue];
            new Random().NextBytes(buffer);
            var tuples = source.Select((m, n) => Tuple.Create<int, T>(buffer[n % byte.MaxValue], m)).ToArray();
            return tuples.OrderBy(m => m.Item1).Select(m => m.Item2);
        }
    }
}
